<?php

/**
 * 任务定时执行控制
 * 
 */
class Autotask_Controller extends Controller {

    var $time;
    var $year;
    var $month;
    var $day;
    var $hour;
    var $minute;
    var $second;
    var $data;

    function _init() {
        $this->time = time();
        $this->year = date("Y");
        $this->month = date("m");
        $this->day = date("d");
        $this->hour = date("H");
        $this->minute = date("i");
        $this->second = date("s");
        set_time_limit(60);
    }

    public function index() {
        $filename = dirname(CACHE_DIR) . '/autotask.time';
        $time = @file_get_contents($filename);
        $data = array('year' => date('Y', $time), 'month' => date('m', $time), 'day' => date('d', $time), 'hour' => date('H', $time), 'minute' => date('i', $time));
        $this->data = $data;
        //每分钟
        if ($this->minute != $data['minute']) {
            @file_put_contents($filename, $this->time);
            try {
                $this->m1();
            } catch (Exception $e) {
                debug($e->getMessage());
            }
        }
        //每小时
        if ($this->hour != $data['hour'] && $this->minute == '00') {
            try {
                $this->h1();
            } catch (Exception $e) {
                debug($e->getMessage());
            }
        }
        //每天
        if ($this->day != $data['day'] && $this->hour == '00' && $this->minute == '00') {
            try {
                $this->d1();
            } catch (Exception $e) {
                debug($e->getMessage());
            }
        }
        echo "success." . date("Y-m-d H:i:s", $this->time) . "." . used_microtime() . "\n";
    }

    //每1分钟
    function m1() {
        $this->crontabtask();
        debug('每分钟,耗时' . used_microtime(), date("Y-m-d H:i:s"));
    }

    //每小时
    function h1() {
        debug('每小时,耗时' . used_microtime(), date("Y-m-d H:i:s"));
    }

    //每天凌晨
    function d1() {
        debug('每一天,耗时' . used_microtime(), date("Y-m-d H:i:s"));
    }

    //定时任务处理
    function crontabtask() {
        //筛选未过期且未完成的任务
        $this->db->query("SELECT * FROM {pre}crontab WHERE state>0 AND state<2 ORDER BY weigh DESC", "crontab");
        while ($row = $this->db->get_array("crontab")) {
            $update = array();
            $execute = false;
            $content = get_json_array($row['content']);
            if ($row['frequence'] == 'once') {
                if ($row['starttime'] > $this->time)
                    continue;
                $execute = true;
            } else {
                if ($this->time < $row['starttime']) {
                    //任务未开始
                } else if ($row['maximums'] && $row['executes'] > $row['maximums']) {
                    //任务已超过最大执行次数
                    $update['state'] = 2;
                } else if ($row['expiretime'] && $this->time > $row['expiretime']) {
                    //任务已过期
                    $update['state'] = -1;
                } else {
                    //重复执行
                    $c = $content['crontime'];
                    $cron = "{$c['minute']} {$c['hour']} {$c['day']} {$c['month']} {$c['week']}";
                    //如果未到执行时间则继续循环
                    if (!is_time_cron($this->time, $cron))
                        continue;
                    $execute = true;
                }
            }
            //如果允许执行
            if ($execute) {
                $update['executetime'] = $this->time;
                $update['executes'] = $row['executes'] + 1;
                $update['state'] = $row['frequence'] == 'once' || ($row['maximums'] && $update['executes'] >= $row['maximums']) ? 2 : 1;

                try {
                    if ($row['type'] == 'module') {
                        //调用模型
                        $this->load->model($content['module']);
                        if (is_object($this->{$content['module']}) && method_exists($this->{$content['module']}, $content['method'])) {
                            $this->{$content['module']}->{$content['method']}();
                        }
                    } else if ($row['type'] == 'url') {
                        //调用URL
                        $url = substr($content['url'], 0, 4) != 'http' ? site_url($content['url'], 1) : $content['url'];
                        post($url);
                    } else if ($row['type'] == 'clearcache') {
                        //清楚缓存
                        $this->cache->clear();
                    }
                } catch (Exception $e) {
                    debug($e->getMessage());
                }
            }
            //如果需要更新状态
            if ($update) {
                $this->db->update("{pre}crontab", $update, array('id' => $row['id']));
            }
        }
    }

    function billtask() {
        set_time_limit(0);
        $curinfo = getdate();
        $todaytime = get_unixtime();
        //筛选未过期且未完成的任务
        $this->db->query("SELECT * FROM {pre}task WHERE state>=0 AND state<2 ORDER BY id ASC", "crontab");
        while ($row = $this->db->get_array("crontab")) {
            $update = array();
            $execute = false;
            if ($this->time < $row['starttime']) {
                //任务未开始
            } else if ($row['maximums'] && $row['executes'] > $row['maximums']) {
                //任务已超过最大执行次数
                $update['state'] = 2;
            } else if ($row['expiretime'] && $this->time > $row['expiretime']) {
                //任务已过期
                $update['state'] = -1;
            } else {
                //判断时分秒是否到达,如果时间在一天中的最后15分钟内则向前提15分钟
                $originalseconds = get_day_after_seconds($row['starttime']);
                if (86400 - $originalseconds < 900)
                    $originalseconds -= 900;
                $currentseconds = get_day_after_seconds();
                //判断时间是否已到
                if ($currentseconds < $originalseconds)
                    continue;
                //判断今天是否有执行,如果已执行则跳过
                if ($row['executetime'] > $todaytime)
                    continue;
                //判断重复类型
                switch ($row['frequency']) {
                    case 'everyday':
                        $execute = true;
                        break;
                    case 'workday':
                        if ($curinfo['wday'] >= 1 && $curinfo['wday'] <= 5)
                            $execute = true;
                        break;
                    case 'workday_fd':
                        $execute = true;
                        break;
                    case 'workday_ds':
                        $thisweek = get_week_of_year();
                        if (($curinfo['wday'] >= 1 && $curinfo['wday'] <= 5) || (($thisweek % 2) > 0 && $curinfo['wday'] == 6))
                            $execute = true;
                        break;
                    case 'workday_dx':
                        if (($curinfo['wday'] >= 1 && $curinfo['wday'] <= 5) || (($curinfo['mday'] % 2) > 0 && $curinfo['wday'] == 6))
                            $execute = true;
                        break;
                    case 'workday_yl':
                        if (($curinfo['wday'] >= 1 && $curinfo['wday'] <= 5) || ($curinfo['wday'] == 6))
                            $execute = true;
                        break;
                    case 'weekend':
                        if ($curinfo['wday'] == 0 || $curinfo['wday'] == 6)
                            $execute = true;
                        break;
                    case 'everyweek':
                        $begintime = get_unixtime('day', 0, 'begin', date("Y", $row['starttime']), date("m", $row['starttime']), date("d", $row['starttime']));
                        if (($todaytime - $begintime ) % (7 * 86400) == 0) {
                            $execute = true;
                        }
                        break;
                    case 'everymonth':
                        $startday = (int) date("d", $row['starttime']);
                        $thisdays = get_month_days();
                        //如果当前的天数小于开始日期的天数则使用开始日期的天数
                        $nextday = $startday > $thisdays ? $thisdays : $startday;
                        $nexttime = get_unixtime('day', 0, 'begin', date("Y"), date("m"), $nextday);
                        if ($row['executetime'] < $nexttime && $this->time >= $nexttime) {
                            $execute = true;
                        }
                        break;
                    default:
                        break;
                }
            }
            //如果允许执行
            if ($execute) {
                if (!isset($this->account->allaccount[$row['account_id']]) || ($row['inaccount_id'] && !isset($this->account->allaccount[$row['inaccount_id']]))) {
                    $account_ids = array_filter(array_unique(array($row['account_id'], $row['inaccount_id'])));
                    if ($account_ids) {
                        $this->db->query("SELECT * FROM {pre}account WHERE id IN (" . implode(",", $account_ids) . ")", "aid");
                        while ($arow = $this->db->get_array("aid")) {
                            $this->account->allaccount[$arow['id']] = $arow;
                        }
                    }
                }
                $update['executetime'] = $this->time;
                $update['executes'] = $row['executes'] + 1;
                $update['state'] = ($row['maximums'] && $update['executes'] >= $row['maximums']) ? 2 : 1;

                try {
                    $value = array();
                    $value['type'] = $row['type'];
                    $value['occurtime'] = $this->time;
                    $value['category_id'] = $row['category_id'];
                    $value['account_id'] = $row['account_id'];
                    $value['inaccount_id'] = $row['inaccount_id'];
                    $value['amount'] = $row['amount'];
                    $value['memo'] = $row['memo'];
                    $value['family'] = $row['family'];
                    $value['createtime'] = $row['modifytime'] = time();
                    $value['user_id'] = $row['user_id'];
                    $value['outstanding'] = 0;
                    $value['task_id'] = $row['id'];
                    $id = $this->db->insert("{pre}bill", $value);

                    if ($value['inaccount_id'] && in_array($value['type'], array('transfer', 'credit'))) {
                        $this->account->update_user_account($value['inaccount_id'], $value['amount'], "新增记账[{$value['memo']}]ID[{$id}],类型[{$value['type']}]");
                    }
                    $amount = $value['type'] == 'income' || (($value['type'] == 'borrow') && $value['category_id'] == 2) ? $value['amount'] : -$value['amount'];
                    $this->account->update_user_account($value['account_id'], $amount, "新增记账[{$value['memo']}],ID[{$id}],类型[{$value['type']}],类别[{$value['category_id']}]");
                } catch (Exception $e) {
                    debug($e->getMessage());
                }
            }
            //如果需要更新状态
            if ($update) {
                $this->db->update("{pre}task", $update, array('id' => $row['id']));
            }
        }
    }

}